package com.sunriz.motordrive.server.common.impl;

import com.sunriz.motordrive.domain.DTO.SetValueDTO;
import com.sunriz.motordrive.domain.DTO.Result;
import com.sunriz.motordrive.server.common.SetValueServer;
import com.sunriz.motordrive.utils.ArrayUtils;
import com.sunriz.motordrive.utils.BaseConversionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;


/**
 * ClassName: SetValueImpl
 * Package: com.sunriz.motordrive.server.impl
 * Description:
 *
 * @Author BuTang
 * @Create 2024/5/13 10:17
 * @Version 1.0
 */
@Slf4j
@Service
public class SetValueServerImpl implements SetValueServer {
    @Autowired
    BaseSerialImpl serialPort;


    /**
     * 单个寄存器点位数据下发
     * @param setValueDTO 从前端传过来的地址&值
     * @return Result类，若下发失败，result.errMsg有错误信息
     */
    @Override
    public Result single(SetValueDTO setValueDTO) {
        if (setValueDTO.getValue()=="" || setValueDTO.getValue()==null){
            return Result.fail("下发数据为空，请输入正确的下发值","403");
        }

        String valueCheck = setValueDTO.getValue();

        if (valueCheck != null && valueCheck.matches("-?\\d+(\\.\\d+)?")) {
        } else {
            return Result.fail("请输入正确的下发值","403");
        }


        List list32 = BaseSerialImpl.list32;

        jssc.SerialPort myPort = BaseSerialImpl.serialPort;
        if (myPort != null ){
            String slaveId = setValueDTO.getSlaveId();
            boolean opened = myPort.isOpened();
            if (opened == true){
                    // 32位数值，使用16功能码下发
                    if (list32.contains(Integer.valueOf(setValueDTO.getAddress()))) {
                        int startAddr = Integer.parseInt(setValueDTO.getAddress());
//                        int value = Integer.parseInt(setValueDTO.getValue());
//                        byte[] startAddrBytes = BaseConversionUtils.intToTwoBytes(startAddr);
//                        byte[] valueBytes = BaseConversionUtils.intToFourBytes(value);
//                        byte[] bytes = new byte[]{Byte.parseByte(slaveId),16,startAddrBytes[0],startAddrBytes[1],0,1,4,valueBytes[0],valueBytes[1],valueBytes[2],valueBytes[3]};

                        // 假设 setValueDTO.getValue() 返回的是字符串 "4294967295"
                        String valueString = setValueDTO.getValue();
                        long value = Long.parseLong(valueString);  // 将字符串转换为 long 类型

                        // 如果传输的是无符号 32 位整数，确保数值范围符合 0 到 4294967295（4 字节）
                        // 将 long 类型的无符号整数转换为 4 字节的字节数组
                        byte[] valueBytes = new byte[4];
                        valueBytes[0] = (byte) (value >> 24);  // 取最高 8 位
                        valueBytes[1] = (byte) (value >> 16);  // 取次高 8 位
                        valueBytes[2] = (byte) (value >> 8);   // 取次低 8 位
                        valueBytes[3] = (byte) (value);        // 取最低 8 位

                        // 将起始地址转换为字节数组
                        byte[] startAddrBytes = BaseConversionUtils.intToTwoBytes(startAddr);

                        // 构建 Modbus 报文字节数组
                        byte[] bytes = new byte[]{
                                Byte.parseByte(slaveId), 16,
                                startAddrBytes[0], startAddrBytes[1],
                                0, 1, 4,
                                valueBytes[0], valueBytes[1], valueBytes[2], valueBytes[3]  // 4 个字节表示一个 32 位无符号整数
                        };


                        BaseSerialImpl.writeFlag = true;
                        Result result = serialPort.sendModbus(bytes);
                        if (result.getSuccess()==true ){
                            return result;
                        }else {
                            return Result.fail("下发32位数值失败，请联系管理员","403");
                        }
                    }else {
                        byte[] basics = {Byte.parseByte(slaveId), 6};
                        byte[] bytes = return06msg(basics, setValueDTO.getAddress(), setValueDTO.getValue());

                        BaseSerialImpl.writeFlag = true;
                        Result result = serialPort.sendModbus(bytes);
                        return result;
                    }
            }
            return Result.fail("串口尚未开启，无法下发","403");
        }else {
            return Result.fail("串口尚未开启，无法下发","403");
        }
    }

    @Override
    public Result check(SetValueDTO setValueDTO) {
        boolean flag = BaseSerialImpl.check06Map.containsKey(setValueDTO.getAddress());
        if (flag){
            BaseSerialImpl.check06Map.remove(setValueDTO.getAddress());

            return Result.success("数据下发成功",null);
        }else {
            log.info("校验到数据下发失败,currentTimeMillis：{}",System.currentTimeMillis());
            return Result.fail("数据下发失败，请重试","403");
        }
    }

    /**
     * 32 Bit Float little-endian 转换为byte数组，然后下发16位报文
     * @param slaveId slaveId
     * @param address 寄存器地址
     * @param value 浮点数，如“12.34”
     */
    @Override
    public void sendFloat(String slaveId, String address, String value) {

        float valueOfFloat = Float.parseFloat(value);

        /**
         * 这里创建了一个 ByteBuffer，其大小为 4 字节，因为 float 类型在 Java 中占用 4 字节。
         * ByteBuffer 是 Java NIO (New Input/Output) 库中的一个类，它提供了对字节数组的读写操作，
         * 并允许设置字节序。
          */
        ByteBuffer bigEndianBuffer = ByteBuffer.allocate(4);

        /**
         * 设置 ByteBuffer 的字节序为 Big-endian，即高位字节放在前面。Big-endian 是一种字节序表示方式
         * 它在多字节数值的存储中，最重要的字节（最高位字节）存储在内存的最低地址。
         */
        bigEndianBuffer.order(ByteOrder.BIG_ENDIAN);

        /**
         * 将之前转换为 float 的值 valueOfFloat 写入 ByteBuffer 中，
         * 并按照 Big-endian 的字节序存储。
         */
        bigEndianBuffer.putFloat(valueOfFloat);
        bigEndianBuffer.flip();

        byte[] bigEndianBytes = bigEndianBuffer.array();
        int addressOfInt = Integer.parseInt(address);

        // 2. 高位字节（从 int 的高 8 位取得）
        byte first = (byte) ((addressOfInt >> 8) & 0xFF);

        // 3. 低位字节（从 int 的低 8 位取得）
        byte last = (byte) (addressOfInt & 0xFF);

        byte[] bytes = {Byte.parseByte(slaveId), 16, first, last,0, 2, 4, bigEndianBytes[3], bigEndianBytes[2], bigEndianBytes[1], bigEndianBytes[0]};
        serialPort.sendModbus(bytes);
    }

    /**
     * 整合modbus报文
     * @param bytes slaveId和功能码
     * @param addr 寄存器点位
     * @param value 值
     * @return 除了crc的完整报文
     */
    public byte[] return06msg(byte[] bytes,String addr ,String value) {
        byte addrLowByte, addrHighByte,valueLowByte,valueHighByte;
        // 获取低字节
        addrLowByte = (byte) (Integer.valueOf(addr) & 0xFF);
        // 获取高字节，通过右移8位再与0xFF进行按位与操作
        addrHighByte = (byte) ((Integer.valueOf(addr) >> 8) & 0xFF);

        // 获取低字节
        valueLowByte = (byte) (Integer.valueOf(value) & 0xFF);
        // 获取高字节，通过右移8位再与0xFF进行按位与操作
        valueHighByte = (byte) ((Integer.valueOf(value) >> 8) & 0xFF);

        byte[] bytes1 = {addrHighByte, addrLowByte, valueHighByte, valueLowByte};
        byte[] bytes2 = ArrayUtils.bytesAddValues(bytes, bytes1);

        return bytes2;
    }
}
